/**
 *  @file BaseObject.cpp
 */
#include "BaseObject.h"
#include "CppMemPool.h"
#include <exception>
#include <typeinfo>

namespace cppflib
{

BaseObject::~BaseObject(void)
{
}

/**
 *  Test whether 2 instances are equal. Derived classes should override and implement their own version
 *
 *  By default, it only checks whether 2 pointers point to the same memory location
 */
bool BaseObject::Equals(const BaseObject &obj) const
{
   return (reinterpret_cast<ptr_t>(this) == reinterpret_cast<ptr_t>(&obj));
}

/**
 *  Allow derived class to proivde their own implementation of digest value
 *
 *  @return hash value of instance address by default
 */
u32_t BaseObject::GetHash(void) const
{
/*
   u32_t h = 0;
   ptr_t t = reinterpret_cast<ptr_t>(this);
   int psize = sizeof(ptr_t);

   for (int i = 0; i < psize; ++i) {
      u32_t htemp = static_cast<u32_t>((t >> (8 * i)) & static_cast<ptr_t>(0xff));
      h ^= (htemp << (((i + htemp) * 53) % 37));
   }

   return h;
*/

   throw "Please implement your own GetHash";
   return 0;
}

/**
 *  Allow derived class to return a human readable string for an instance
 *
 *  @return empty string by default
 */
pcwstr_t BaseObject::ToString(void) const
{
   return _S("BaseObject");
}

/**
 *  Test whether type of 'this' equals to 'obj'
 */
bool BaseObject::EqualType(const BaseObject &obj) const
{
   const std::type_info &thisInfo = typeid(*this);
   const std::type_info &objInfo = typeid(obj);
   return (thisInfo == objInfo);
}

/**
 *  Overloaded to allocate memory and put it on the current auto release pool
 */
void *BaseObject::operator new(sz_t size)
{
   // call the global one in CppMemPool
   return ::operator new(size, cppflib::cppmempool::NEWCLASS);
}

/**
 *  This should not be called directly. Use cppmempool::Release instead.
 */ 
void BaseObject::operator delete(void *p)
{
   // use this to check whether this 'operator delete' function is called during an exception
   if (std::uncaught_exception()) {
      cppmempool::Release(p);
   }
   else {
      throw "Don't call delete directly! Use 'cppflib::cppmempool::Release' instead.";
   }
}

/**
 *  Actually, this should not be called since it will throw exception.
 *  Instead, allocate an array of pointers and instantiate a new instance for each slot
 */
void *BaseObject::operator new[](sz_t size)
{
   return ::operator new[](size, cppflib::cppmempool::NEWCLASS);
}

/**
 *  Again, this should not be called
 */
void BaseObject::operator delete[](void *p)
{
   cppmempool::Release(p);
}


} // end of namespace cppflib
